"""
旧串口数据读取并处理之后送给解码器

"""
import os
import random
import struct
import time
import threading
from datetime import datetime
from typing import Dict, Optional, Callable
import serial
from serial.tools import list_ports
import numpy as np

from data_visualizer import DataVisualizer
from raw_data_saver import DataSaver
from monkey_decode import MonkeyDecoder
from requeue import Requeue

frequency_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x02, 0x03, 0xe8, 0x00, 0x00, 0x00,
                 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xf0]  # 采样率1kHz
frequency_cmd_500 = [0x55, 0xaa, 0x00, 0x06, 0x0c, 0x02, 0x02, 0x01, 0xf4, 0x00, 0x00, 0x00,
                     0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0]  # 采样率500Hz
channel_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff,
               0xff, 0xff, 0xff, 0xff, 0xff, 0x0F, 0xf0]  # 64通道
channel_cmd_60 = [0x55, 0xAA, 0x00, 0x06, 0x0C, 0x02, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
                  0x7D, 0xDF, 0x7F, 0xFF, 0xFF, 0x2B, 0xF0]  # 60通道
start_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xf0]  # 开始采集
end_cmd = [0x55, 0xaa, 0x00, 0x00, 0x0c, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00,
           0x00, 0x00, 0x00, 0x00, 0x00, 0xB5, 0xf0]  # 停止采集


class SerialPacketProcessor:
    def __init__(self, max_queue_size, decoder, port_name, serial_processor):
        """
        初始化串口数据处理器

        参数:
            max_queue_size: 接收队列最大容量
            decoder：解码器
        """
        self.port_name = port_name
        self.decoder = decoder
        self.channel_num = self.decoder.channel_num
        self.decode_step = self.decoder.step_size
        self.serial_processor = serial_processor
        # self.serial_processor.open_serial_port(port_name)

        self.data_stream = bytearray()  # 累积的帧数据流

        # ECoG数据缓冲区 (60通道)
        self.ecog_data = []
        self.ecog_counter = 0  # 累积的数据点计数
        # 创建接收队列
        self.ecog_queue = Requeue(500)  # 存储传输给解码线程的数据

        # 创建接收队列
        self.receive_queue = Requeue(max_queue_size)
        self.tmp_buffer = bytearray()
        # 数据回调函数
        self.data_callback = None
        self.data_saver = DataSaver(r"data", frame_size=1000, file_size_m=60, file_size_h=60)
        # self.serial_port = None
        self.running = False
        # 创建处理线程
        self.processing_thread = threading.Thread(target=self._processing_loop, daemon=True)
        # 读取线程
        self.read_thread = threading.Thread(target=self._read_data,
                                            daemon=True)
        # self.read_thread = threading.Thread(target=self.raw_test,
        #                                     args=(
        #                                         r"E:\ZHNJ\13-ECOG\猴子\0807\20250807_111958_上下二向_round1\20250807_111958\01",),
        #                                     daemon=True)
        self.total_read = 0
    def start(self):
        """启动处理线程"""
        if not self.running:
            self.running = True
            self.processing_thread.start()

            self.read_thread.start()

    def stop(self):
        """停止处理线程"""
        self.running = False
        # 关闭串口
        if self.serial_processor and self.serial_processor.serial_port.is_open:
            print("serial_port_process stop")
            self.serial_processor.send_command(bytearray(end_cmd))
            print("正在关闭串口...")
            self.serial_processor.close_serial_port()
            print("串口已关闭")
        if self.processing_thread.is_alive():
            self.processing_thread.join(timeout=1.0)
        if self.read_thread.is_alive():
            self.read_thread.join(timeout=1.0)
        if self.data_saver:  # 关闭文件，防止泄露
            self.data_saver.close()

    def register_callback(self, callback):
        """注册数据处理回调函数"""
        self.data_callback = callback

    def add_packet(self, packet):
        """
        添加从串口读取的数据包(240字节)到接收队列

        返回:
            bool: 数据包是否成功加入队列
        """
        if self.receive_queue.isFull():
            print("警告: 接收队列已满，尝试等待空间...")
            return False

        # 将数据包放入队列
        self.receive_queue.push(packet)
        return True

    def _processing_loop(self):
        """
        数据处理主循环
        :return:
        """
        # 处理线程的主循环
        while self.running:
            if self.receive_queue.isEmpty():
                time.sleep(0.001)
                continue
            else:
                try:
                    # 从队列获取数据包
                    packet = self.receive_queue.pop()
                    # 处理数据包
                    if packet:
                        self.extend_packet(packet)

                except Exception as e:
                    print(f"处理错误: {str(e)}")

    def extend_packet(self, packet):
        """
        串口读的数据进行追加，防止读取的240字节不是一个完整的数据packet
        :param packet:
        :return:
        """
        self.data_stream.extend(packet)
        self._parse_data_segments()

    def _parse_data_segments(self):
        # packet = bytearray()
        """ 解析数据包130
        格式:
          2字节帧头(55 AA)  3字节大端序号  2字节温度  1字节标记  120字节小端数据  1字节CRC  1字节帧尾(F0)
          """
        while len(self.data_stream) >= 130:
            # 检查帧头 (55 AA)
            if self.data_stream[0] == 0x55 and self.data_stream[1] == 0xAA and self.data_stream[129] == 0xF0:
                # 提取数据段(130字节)
                segment = bytes(self.data_stream[:130])
                del self.data_stream[:130]
                # 在线排序没有意义，并且会延迟，所以直接处理
                self._process_single_segment(segment)
            else:
                # 帧头或帧尾不匹配，丢弃第一个字节
                # print("帧头或帧尾不匹配：", hex(self.data_stream[0]),hex(self.data_stream[1]),hex(self.data_stream[129]))
                del self.data_stream[0]
                continue

    def _process_single_segment(self, segment):
        """
        处理单个数据段(130字节)

        格式:
          2字节帧头(55 AA)  3字节大端序号  2字节温度  1字节标记  120字节小端数据  1字节CRC  1字节帧尾(F0)
        """
        # 提取数据
        ecog_data = segment[8:128]  # 120字节数据(小端)

        # 保存到文件
        self.tmp_buffer += segment[2:5]  # 3包头
        self.tmp_buffer += ecog_data  # 120实际数据
        if len(self.tmp_buffer) >= 123 * 20:  # 累计20个包写一次，需要根据实际修改
            # print("write")
            self.data_saver.write_to_file(self.tmp_buffer)
            del self.tmp_buffer[:123 * 20]

        # 解析60通道数据（小端16位有符号整数）
        channels = []
        for i in range(60):
            # 每个通道2字节
            start_idx = i * 2
            end_idx = start_idx + 2
            value = int.from_bytes(ecog_data[start_idx:end_idx], 'little', signed=False)  # 无符号短整型
            channels.append((value / 6553.6 - 5))

        # 添加到ECoG缓冲区
        self._add_to_ecog_buffer(channels)

    def _add_to_ecog_buffer(self, channels):
        """将60通道数据添加到缓冲区"""
        # 将数据添加到每个通道的缓冲区
        self.ecog_data.append(channels)
        # 更新计数器
        self.ecog_counter += 1

        # 检查是否累积了self.decode_step个时间点
        if self.ecog_counter >= self.decode_step:
            self._process_ecog_block()

    def _process_ecog_block(self):
        """处理累积的self.decode_step个ECoG点"""
        # 创建60×self.decode_step的numpy数组
        block = np.zeros((self.decode_step, self.channel_num), dtype=np.float32)
        # 填充数据
        block[:, :] = self.ecog_data[:self.decode_step]
        # 移除已处理的数据
        del self.ecog_data[:self.decode_step]

        # 更新计数器
        self.ecog_counter -= self.decode_step

        self.decoder.read_data(block)  # 传递给解码线程

    def _read_data(self):
        try:
            # self.serial_processor.send_command(bytearray(frequency_cmd_500))  # 设置频率
            # res = self.serial_processor.read_data(240)
            # if res[0] == 0x55 and res[1] == 0xAA and res[2] == 0x4F and res[3] == 0x4B and res[4] == 0x04 and res[
            #     5] == 0xF0:
            #     print("频率设置成功")
            # self.serial_processor.send_command(bytearray(channel_cmd_60))
            # res = self.serial_processor.read_data(240)
            # if res[0] == 0x55 and res[1] == 0xAA and res[2] == 0x4F and res[3] == 0x4B and res[4] == 0x04 and res[
            #     5] == 0xF0:
            #     print("通道设置成功")
            self.serial_processor.send_command(bytearray(start_cmd))
            timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S%f")[:-3]
            self.data_saver.create_new_file(timestamp)
            while self.running:
                packet = self.serial_processor.read_data(240*3)
                if packet:
                    self.total_read += 240*3
                    self.add_packet(packet)
        except Exception as e:
            print(f"串口错误: {str(e)}")

    def raw_test(self, base_directory):
        frame_data = bytearray()  # 跨文件累积的缓冲区
        frame_size = 130  # 单帧固定长度
        packet_size = 240  # 数据包固定长度
        raw_block_size = 123  # 每个.raw数据块大小（3+120）

        # 1. 收集所有.raw文件并按文件名排序（避免os.walk默认顺序混乱）
        raw_files = []
        for root, _, files in os.walk(base_directory):
            for file in files:
                if file.endswith('.raw'):
                    raw_files.append(os.path.join(root, file))
        # 按文件名排序（确保处理顺序可预期）
        raw_files.sort()

        for file_path in raw_files:
            file_name = os.path.basename(file_path)
            frame_count = 0  # 记录当前文件处理的帧数
            try:
                with open(file_path, 'rb') as f:

                    while True:
                        # 2. 按123字节块读取（确保每个块完整）
                        # 读取3字节包头+120字节数据，共123字节
                        block = f.read(raw_block_size)
                        if len(block) != raw_block_size:
                            # 文件末尾可能有不完整块，忽略并记录
                            if block:
                                print(f"文件{file_name}末尾有{len(block)}字节不完整数据，已忽略")
                            break  # 退出当前文件读取

                        # 3. 拆分包头和数据（从完整块中提取）
                        seq_num_bytes = block[:3]  # 前3字节是包头
                        data_bytes = block[3:]  # 后120字节是数据

                        # 4. 组装130字节帧（严格校验长度）
                        segment = bytearray()
                        segment.extend([0x55, 0xAA])  # 帧头(2)
                        segment.extend(seq_num_bytes)  # 序号(3)
                        segment.extend([0x00, 0x25])  # 温度(2)
                        segment.append(0x01)  # 标记(1)
                        segment.extend(data_bytes)  # 数据(120)
                        segment.append(0x00)  # CRC(1)
                        segment.append(0xF0)  # 帧尾(1)
                        # 校验帧长度（避免组装错误）
                        if len(segment) != frame_size:
                            print(
                                f"警告：{file_name}第{frame_count}帧组装错误，长度应为{frame_size}，实际{len(segment)}，已跳过")
                            continue  # 跳过错误帧，不影响后续处理

                        # 5. 累积到缓冲区并拆分数据包
                        frame_data.extend(segment)
                        frame_count += 1

                        # 当缓冲区足够时，持续拆分240字节包
                        while len(frame_data) >= packet_size:
                            packet = frame_data[:packet_size]
                            del frame_data[:packet_size]
                            self.add_packet(packet)
                            # 打印调试信息（可选）
                            # print(f"发送数据包（{file_name}第{frame_count}帧参与），剩余缓冲{len(frame_data)}字节")
                            time.sleep(0.01)

                # print(f"文件{file_name}处理完成，共处理{frame_count}帧")

            except Exception as e:
                # 单个文件处理出错不影响其他文件
                print(f"处理文件{file_name}时出错：{str(e)}，已跳过该文件")
                continue  # 继续处理下一个文件

        # 处理所有文件结束后的剩余数据
        if frame_data:
            print(f"\n所有文件处理完成，发送剩余{len(frame_data)}字节数据")
            self.add_packet(frame_data)

    def get_read_num(self):
        return self.total_read

    def set_read_num(self, num):
        self.total_read = num


# 测试代码
if __name__ == "__main__":
    decoder = MonkeyDecoder(
        model_path=r"./model/lda_model_0811.pkl",
        #  "D:\PycharmProjects\EcogProject\monkey\20250731\test_lda_0812_.joblib",
        window_size=256,
        step_size=32,
        channel_num=60,
        is_mat=False
    )
    processor = SerialPacketProcessor(max_gap=64, max_queue_size=500, decoder=decoder, port_name='COM9')
    processor.start()

    try:
        while True:
            pass
    finally:
        processor.stop()
